package com.turnengine.client.common.command.executor.data;

import static com.javabi.common.dependency.DependencyFactory.getDependency;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import com.javabi.command.ICommandRequestList;
import com.javabi.command.ICommandResponseList;
import com.javabi.command.IExecutableCommand;
import com.javabi.command.IExecutableCommandResponse;
import com.javabi.command.response.CommandRequestList;
import com.javabi.command.response.CommandResponseList;
import com.javabi.command.serializer.ICommandDataSerializer;
import com.javabi.command.serializer.ICommandDataSerializerLookup;
import com.javabi.common.io.data.DataReader;
import com.javabi.common.io.data.DataWriter;
import com.javabi.common.io.data.IDataReader;
import com.javabi.common.io.data.IDataWriter;
import com.javabi.common.lang.UncheckedException;
import com.turnengine.client.common.command.client.ICommandStream;

public class CommandDataStream implements ICommandStream {

	private final ICommandDataSerializerLookup serializerLookup;

	public CommandDataStream() {
		this.serializerLookup = getDependency(ICommandDataSerializerLookup.class);
	}

	@Override
	public String toString(ICommandRequestList requestList) {
		return requestList.toString();
	}

	@Override
	public String toString(ICommandResponseList responseList) {
		return responseList.toString();
	}

	@Override
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void writeRequestList(ICommandRequestList requestList, OutputStream output) {
		try {
			IDataWriter writer = new DataWriter(output);
			int size = requestList.size();
			writer.writePositiveInt(size);

			// Write response list
			for (int i = 0; i < size; i++) {

				// Read response
				IExecutableCommand request = requestList.get(i);
				short commandId = request.getCommandId();
				writer.writeShort(commandId);
				ICommandDataSerializer<?> serializer = serializerLookup.getSerializer(commandId);
				serializer.writeRequest(writer, request);
			}
		} catch (IOException ioe) {
			throw new UncheckedException(ioe);
		}
	}

	@Override
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void writeResponseList(ICommandResponseList responseList, OutputStream output) {
		try {
			IDataWriter writer = new DataWriter(output);
			int size = responseList.size();
			writer.writePositiveInt(size);

			// Write response list
			for (int i = 0; i < size; i++) {

				// Read response
				IExecutableCommandResponse response = responseList.get(i);
				short commandId = response.getCommandId();
				writer.writeShort(commandId);
				ICommandDataSerializer<?> serializer = serializerLookup.getSerializer(commandId);
				serializer.writeResponse(writer, response);
			}
		} catch (IOException ioe) {
			throw new UncheckedException(ioe);
		}
	}

	@Override
	public ICommandResponseList readResponseList(InputStream input) {
		try {
			IDataReader reader = new DataReader(input);
			int size = reader.readPositiveInt();
			if (size == 0) {
				throw new IOException("read size of zero, no commands in response list??");
			}

			// Read response list
			CommandResponseList list = new CommandResponseList();
			for (int i = 0; i < size; i++) {

				// Read response
				short commandId = reader.readShort();
				ICommandDataSerializer<?> serializer = serializerLookup.getSerializer(commandId);
				IExecutableCommandResponse<?> response = serializer.readResponse(reader);
				list.add(response);
			}

			// Done
			return list;
		} catch (IOException ioe) {
			throw new UncheckedException(ioe);
		}
	}

	@Override
	public ICommandRequestList readRequestList(InputStream input) {
		try {
			IDataReader reader = new DataReader(input);
			int size = reader.readPositiveInt();
			if (size == 0) {
				throw new IOException("read size of zero, no commands in response list??");
			}

			// Read request list
			CommandRequestList list = new CommandRequestList();
			for (int i = 0; i < size; i++) {

				// Read request
				short commandId = reader.readShort();
				ICommandDataSerializer<?> serializer = serializerLookup.getSerializer(commandId);
				IExecutableCommand<?> request = serializer.readRequest(reader);
				list.add(request);
			}

			// Done
			return list;
		} catch (IOException ioe) {
			throw new UncheckedException(ioe);
		}
	}

}
